use std::collections::HashMap;

use i_triangle::{i_overlay::{core::{fill_rule::FillRule, overlay::ShapeType, overlay_rule::OverlayRule}, f64::overlay, i_float::f64_point::F64Point, i_shape::f64::shape::F64Shapes}, triangulation::float::FloatTriangulate};
use serde::Serialize;
use tiled::Layer;

use crate::tmx_loader::map::{get_bornpoint, get_object_polygon, get_static_object_datas};

use super::{layer::LayerType, navmesh::{NavMesh, Polygon, Polygons}, visual_data};

#[derive(Debug, Clone, Serialize)]
pub struct BornPointInfo {
    pub pos:F64Point,
    pub name:String,
}

#[derive(Debug, Clone, Serialize)]
pub struct MarkedAreaInfo {
    pub polygon:Vec<F64Point>,
    pub name:String,
}

#[derive(Debug, Clone, Serialize)]
pub struct MarkedPointInfo {
    pub pos:F64Point,
    pub name:String,
}

#[derive(Debug, Clone, Serialize)]
pub struct TmxData {
    navmesh:NavMesh,
    born_points:Vec<BornPointInfo>,
    marked_areas:std::collections::HashMap<String, Vec<MarkedAreaInfo>>,
    orientation:u8,
    size:(u32, u32),
    marked_points:HashMap<String, Vec<MarkedPointInfo>>,
    event_areas:HashMap<String, Vec<Vec<F64Point>>>,
    map_visual_data:visual_data::TmxVisualData,
}

fn convert_layer_polygon(layer:&Layer, polygon: Vec<(f32, f32)>)-> Vec<(f32, f32)> {
    let mut polygons = Vec::new();
    for point in polygon {
        polygons.push((point.0 + layer.offset_x, point.1 - layer.offset_y));
    }
    polygons
}

impl From<super::MapData> for TmxData {
    fn from(map_data: super::MapData) -> Self {
        let map = &map_data.map;
        let mut walkable_polygons: Vec<Vec<(f32, f32)>> = Vec::new(); // 可行走的多边形区域列表
        let mut collision_polygons: Vec<Vec<(f32, f32)>> = Vec::new(); // 碰撞的多边形区域列表
        let mut born_points:Vec<BornPointInfo> = Vec::new();//出生点位标记
        let mut marked_areas:HashMap<String, Vec<MarkedAreaInfo>> = HashMap::new();
        let mut marked_points:HashMap<String, Vec<MarkedPointInfo>> = HashMap::new();
        let mut event_areas:HashMap<String, Vec<Vec<F64Point>>> = HashMap::new();
        for layer in map.layers() {
            match layer.layer_type() {
                tiled::LayerType::Objects(data) => {
                    let Some(ref layer_type) = layer.user_type else {
                        println!("skip object layer {}", layer.name);
                        continue;
                    };
                    match LayerType::from(layer_type.as_str()) {
                        LayerType::Walkable => {
                            println!("try convert object layer {}", layer.name);
                            for obj in data.objects() {
                                let Some(polygon) = get_object_polygon(Some(&map), &obj, None) else {continue;};
                                walkable_polygons.push(convert_layer_polygon(&layer, polygon));
                            }
                        }
                        LayerType::Collision => {
                            for obj in data.objects() {
                                let Some(polygon) = get_object_polygon(Some(&map), &obj, None) else {continue;};
                                collision_polygons.push(convert_layer_polygon(&layer, polygon));
                            }
                        }
                        LayerType::StaticObject => {
                            println!("try convert object layer {}", layer.name);
                            for obj in data.objects() {
                                let Some(polygons) = get_static_object_datas(&map, &obj, LayerType::Collision) else {continue;};
                                for polygon in polygons {
                                    collision_polygons.push(convert_layer_polygon(&layer, polygon));
                                }
                            }
                        }
                        LayerType::Ground => {
                            println!("try convert object layer {}", layer.name);
                            for obj in data.objects() {
                                let Some(polygons) = get_static_object_datas(&map, &obj, LayerType::Walkable) else {continue;};
                                for polygon in polygons {
                                    walkable_polygons.push(convert_layer_polygon(&layer, polygon));
                                }
                            }
                        }
                        LayerType::BornPoints => {
                            println!("try convert object layer {}", layer.name);
                            for obj in data.objects() {
                                let Some(born_point) = get_bornpoint(Some(&map), &obj) else {continue;};
                                born_points.push(born_point);
                            }
                        }
                        LayerType::Unknown => {
                            println!("unknown user layer type:{} in layer {}", layer_type, layer.name);
                        }
                        LayerType::MarkedArea(area_type) => {
                            println!("try convert object layer {}:Marked:{}", layer.name, area_type);
                            for obj in data.objects() {
                                let Some(polygon) = get_object_polygon(Some(&map), &obj, None) else {continue;};
                                let mut f64_points = Vec::new();
                                let translate_polygon = convert_layer_polygon(&layer, polygon);
                                for point in translate_polygon {
                                    f64_points.push(F64Point::new(point.0 as f64, point.1 as f64));
                                }
                                marked_areas.entry(area_type.clone()).or_insert(Vec::new()).push(MarkedAreaInfo {
                                    polygon:f64_points,
                                    name: obj.name.clone()
                                });
                            }
                        },
                        LayerType::MarkedPoint(area_type) => {
                            println!("try convert object layer {}:Marked:{}", layer.name, area_type);
                            for obj in data.objects() {
                                let Some(born_point) = get_bornpoint(Some(&map), &obj) else {continue;};
                                marked_points.entry(area_type.clone()).or_insert(Vec::new()).push(MarkedPointInfo {
                                    pos:born_point.pos,
                                    name: obj.name.clone()
                                });
                            }
                        },
                        LayerType::AutoGround => {
                            println!("try convert object layer {}", layer.name);
                            for obj in data.objects() {
                                let Some(polygons) = get_static_object_datas(&map, &obj, LayerType::Walkable) else {continue;};
                                for polygon in polygons {
                                    walkable_polygons.push(convert_layer_polygon(&layer, polygon));
                                }
                            }
                            
                            for obj in data.objects() {
                                let Some(polygons) = get_static_object_datas(&map, &obj, LayerType::Collision) else {continue;};
                                for polygon in polygons {
                                    collision_polygons.push(convert_layer_polygon(&layer, polygon));
                                }
                            }

                            for obj in data.objects() {
                                match LayerType::from(obj.user_type.as_str()) {
                                    LayerType::Walkable => {
                                        let Some(polygon) = get_object_polygon(Some(&map), &obj, None) else {continue;};
                                        walkable_polygons.push(convert_layer_polygon(&layer, polygon));
                                    },
                                    LayerType::Collision => {
                                        let Some(polygon) = get_object_polygon(Some(&map), &obj, None) else {continue;};
                                        collision_polygons.push(convert_layer_polygon(&layer, polygon));
                                    },
                                    _ => {
                                        continue;
                                    }
                                }
                            }

                        }
                        LayerType::EventArea => {
                            println!("try convert object layer {}", layer.name);
                            for obj in data.objects() {
                                let Some(polygon) = get_object_polygon(Some(&map), &obj, None) else {continue;};
                                let mut f64_points = Vec::new();
                                let translate_polygon = convert_layer_polygon(&layer, polygon);
                                for point in translate_polygon {
                                    f64_points.push(F64Point::new(point.0 as f64, point.1 as f64));
                                }
                                let name = if obj.name.is_empty() {
                                    format!("event_area_{}", obj.id())
                                } else {
                                    obj.name.clone()
                                };
                                event_areas.entry(name).or_insert(Vec::new()).push(f64_points);
                            }
                        },
                    }
                }
                _ => {
                    println!("skip layer {}", layer.name);
                }
            }
        }

        let mut difference_shapes:F64Shapes = Vec::new();
        for polygon in collision_polygons {
            let f32_points = polygon.iter().map(|point| F64Point::new(point.0 as f64, point.1 as f64)).collect();
            difference_shapes.push(vec![ensure_clockwise(f32_points)]);
        }

        //尝试对difference_polygons 进行布尔合并
        difference_shapes = try_merge_polygons(difference_shapes);

        let mut target_shapes:F64Shapes = Vec::new();
        for polygon in walkable_polygons {
            let f32_points = polygon.iter().map(|point| F64Point::new(point.0 as f64, point.1 as f64)).collect();
            target_shapes.push(vec![ensure_clockwise(f32_points)]);
        }
        //尝试对target_polygons 进行布尔合并
        target_shapes = try_merge_polygons(target_shapes);

        //再尝试对合并后的target_polygons进行布尔差集运算去除碰撞区域，再进行三角剖分得到可行走区域
        let mut merged_walkable_shapes:F64Shapes = Vec::new();
        for target_polygon in target_shapes {
            let mut overlay = overlay::F64Overlay::new();
            overlay.add_paths(target_polygon, ShapeType::Subject);
            for difference_polygon in &difference_shapes {
                // target_data.push(difference_polygon.to_vec());
                overlay.add_paths(difference_polygon.to_vec(), ShapeType::Clip);
            }
            let graph = overlay.into_graph(FillRule::NonZero);
            let result_shapes = graph.extract_shapes(OverlayRule::Difference);
            for target_data in result_shapes {
                if target_data.is_empty() {
                    continue;
                }
                merged_walkable_shapes.push(target_data);
            }
        }

        // 合并连接在一起的多边形
        merged_walkable_shapes = try_merge_polygons(merged_walkable_shapes);
        
        let mut polygons = Polygons::new();
        for (index, polygon) in merged_walkable_shapes.iter().enumerate() {
            let result = polygon.to_convex_polygons(Some(FillRule::NonZero), 0.0);
            for path in result {
                polygons.add_polygon(Polygon::with_points(&path, index));
            }
        }


        //开始处理event_areas，首先把相同名字的区域合并
        let mut new_event_areas:HashMap<String, Vec<Vec<F64Point>>> = HashMap::new();
        for (name, areas) in event_areas {
            let new_shapes:F64Shapes = try_merge_polygons(areas.iter().map(|path|{
                vec![path.clone()]
            }).collect());
            let mut new_area = Vec::new();
            for shape in new_shapes {
                let polygon = shape.to_convex_polygons(Some(FillRule::NonZero), 0.0);
                new_area.extend(polygon);
            }
            new_event_areas.insert(name, new_area);
        }
        
        Self {
            navmesh:NavMesh::new(polygons, merged_walkable_shapes),
            born_points,
            marked_areas,
            marked_points,
            orientation:map.orientation as u8,
            size:(map.width * map.tile_width, map.height * map.tile_height),
            event_areas: new_event_areas,
            map_visual_data:visual_data::TmxVisualData::from(&map_data),
        }
    }
}

fn try_merge_polygons(targets:F64Shapes)->F64Shapes{
    if targets.is_empty() {
        return targets;
    }
    let mut overlay = overlay::F64Overlay::new();
    // 将第一个多边形作为 Subject
    for target_polygon in targets.iter() {
        overlay.add_paths(target_polygon.clone(), ShapeType::Subject);
    }

    overlay.into_graph(FillRule::NonZero).extract_shapes(OverlayRule::Union)
}

fn is_clockwise(points: &Vec<F64Point>) -> bool {
    let mut sum = 0.0;
    
    // 使用Shoelace定理来计算面积
    for i in 0..points.len() {
        let p1 = points[i];
        let p2 = points[(i + 1) % points.len()]; // 下一个点，首尾相连
        sum += (p2.x - p1.x) * (p2.y + p1.y);
    }

    // 如果结果为正数，则顺时针；负数则逆时针
    sum > 0.0
}

// 确保输入的点按顺时针顺序返回
fn ensure_clockwise(mut points: Vec<F64Point>) -> Vec<F64Point> {
    if !is_clockwise(&points) {
        // 如果不是顺时针，则反转向量
        points.reverse();
    }
    points
}
